package pingu.interface_graphique;

import java.awt.Font;
import java.util.ArrayList;
import java.util.Iterator;

import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.TrueTypeFont;
import org.newdawn.slick.gui.TextField;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

import pingu.joueur.Joueur;
import pingu.monde.Case;
import pingu.monde.Pingouin;
import pingu.monde.Plateau;


public class GameplayState extends BasicGameState{

	private int stateId = 0;


	private enum STATES {
		PARAMETERS_GAME_STATE, PLACE_PIECE_STATE, SELECT_PIECE_STATE, 
		SELECT_CASE_STATE,MOVING_PIECE_STATE, PAUSE_STATE, GAME_OVER_STATE,RETURN_TO_MENU_STATE
	}

	private STATES currentState = null;
	private GameContainer container;
	private Image caseHexa;
	private Image caseSelection;
	private Image poisson1;
	private Image poisson2;
	private Image poisson3;
	private Image pinguCouleur;
	private Image pinguDessus;
	private Image pinguSelection;

	private int largHexa;
	private int hautHexa;
	private int hauteurFenetre;
	private int largeurFenetre;
	private int largeurP;
	private int hauteurP;
	private int xMin;
	private int yMin;
	private float scale;
	private Plateau plateau;
	private ArrayList<Joueur> joueurs;
	private int joueurCourant=0;
	private TextFieldWithImage nbJoueursField;
	private TextFieldWithImage nbPingouinsField;
	private TextFieldWithImage nbCasesField;
	private TextFieldWithImage pseudoField;
	private MouseOverButton couleursImage;
	private MouseOverButton okButton;
	private MouseOverButton cpu;
	private MouseOverButton humain;
	private MouseOverButton suivantImage;
	private ArrayList<HexagonalButton> listHexagonalButtons;
	private MouseOverButton nouvellePartie;





	public GameplayState(int stateId)
	{
		this.stateId = stateId;
	}

	@Override
	public int getID() {
		return stateId;
	}

	@Override
	public void init(GameContainer gc, StateBasedGame sb) throws SlickException {
		this.container=gc;
		try {
			//container.setShowFPS(false);

			caseHexa = new Image("img/glace.png");
			caseSelection = new Image("img/glaceSelection.png");
			poisson1 = new Image("img/1poisson.png");
			poisson2 = new Image("img/2poisson.png");
			poisson3 = new Image("img/3poisson.png");
			pinguCouleur= new Image("img/pinguCouleur.png");
			pinguDessus= new Image("img/pinguDessus.png");
			pinguSelection= new Image("img/pinguSelection.png");
			largHexa=caseHexa.getWidth();hautHexa=caseHexa.getHeight();
			hauteurFenetre=container.getHeight();
			largeurFenetre=container.getWidth();

			xMin=20;yMin=120;

			//default initialization
			int nbPingouins=4;
			int nbJoueurs =2;
			int nbCases=110;
			initParametres(nbCases,nbJoueurs,nbCases);
			initBoard();

			Font font=new Font("Verdana",Font.PLAIN,20);
			TrueTypeFont myFont = new TrueTypeFont(font, true);

			nbJoueursField=new TextFieldWithImage(gc, new Image("img/nbJoueurs.png"), 20, 100, 2,nbJoueurs+"");

			nbPingouinsField=new TextFieldWithImage(gc, new Image("img/nbPingouins.png"), 20, 200, 1, nbPingouins+"");

			nbCasesField=new TextFieldWithImage(gc, new Image("img/nbCases.png"), 20, 300,4,nbCases+"");

			pseudoField=new TextFieldWithImage(gc, new Image("img/pseudo.png"), largeurFenetre-300, 330,10,joueurs.get(0).getPseudo());

			couleursImage= new MouseOverButton(gc, new Image("img/spectre.png"), largeurFenetre-280, 100);
			suivantImage= new MouseOverButton(gc, new Image("img/suivant.png"), largeurFenetre-295, 450);

			cpu=new MouseOverButton(gc, new Image("img/cpu.png"), largeurFenetre-150, 400);
			humain=new MouseOverButton(gc, new Image("img/humain.png"), largeurFenetre-150, 400);
			
			okButton=new MouseOverButton(gc, new Image("img/ok.png"), largeurFenetre-150, hauteurFenetre-150);
			okButton.setMouseOverImage(new Image("img/okSelection.png"));

			nouvellePartie=new MouseOverButton(gc, new Image("img/nouvellePartie.png"), largeurFenetre-300, 10);

		} catch (SlickException e) {
			e.printStackTrace();
		} 

	}

	private void initParametres(String nbCases,String nbJoueurs,String nbPingouins)
	{
		int myNbCases = 110;
		int myNbJoueurs= 2;
		int myNbPingouins =4;
		try {
			myNbCases=new Integer(nbCases);
		} catch (Exception e) {}
		try {
			myNbJoueurs=new Integer(nbJoueurs);
		} catch (Exception e) {}
		try {
			myNbPingouins=new Integer(nbPingouins);
		} catch (Exception e) {}

		initParametres(myNbCases, myNbJoueurs, myNbPingouins);
	}

	private void initParametres(int nbCases,int nbJoueurs,int nbPingouins)
	{
		if(nbCases<1)nbCases=1;
		if(nbJoueurs<1)nbJoueurs=1;
		if(nbPingouins<1)nbPingouins=1;

		plateau= new Plateau(nbCases);
		largeurP=plateau.getLargeur();
		hauteurP=plateau.getHauteur();

		scale=(float) Math.min((double)(largeurFenetre-2*xMin)/(double)(largHexa*largeurP),
				(double)(hauteurFenetre-1*yMin)/(double)((hautHexa-largHexa*0.25f)*(hauteurP+1)));


		if(joueurs==null){
			joueurs=new ArrayList<Joueur>();
			for (int j = 0; j < nbJoueurs; j++) {
				joueurs.add(new Joueur("Joueur"+(j+1), 
						new Color((float)Math.random(),(float)Math.random(),(float)Math.random()),
						nbPingouins, true,true));
			}
		}
		else{
			for (int j = 0; j < joueurs.size(); j++) {
				Joueur jCourant=joueurs.get(j);
				jCourant.setNbPingouins(nbPingouins);
			}

			while(joueurs.size()>nbJoueurs){
				joueurs.remove(joueurs.size()-1);
			}
			while(joueurs.size()<nbJoueurs){
				joueurs.add(new Joueur("Joueur"+(joueurs.size()+1), 
						new Color((float)Math.random(),(float)Math.random(),(float)Math.random()),
						nbPingouins, true,true));
			}
		}
	}

	@Override
	public void enter(GameContainer gc, StateBasedGame sb) throws SlickException
	{
		super.enter(gc, sb);
		currentState = STATES.PARAMETERS_GAME_STATE;
		/**
		 * TODO a changer , si en mode multi on commence pas � parametre mais �
		 *  place piece pour le j Courant (random)
		 */
	}

	@Override
	public void render(GameContainer gc, StateBasedGame sb, Graphics g) throws SlickException {
		if(currentState==STATES.PARAMETERS_GAME_STATE)
		{
			drawParametersPage(g);
		}
		else if (currentState==STATES.GAME_OVER_STATE) {
			drawGameOver(g);
		}
		else{

			drawBoard(g);

			if (currentState==STATES.PAUSE_STATE) {
				drawPause();
			}
		}
	}

	@Override
	public void update(GameContainer gc, StateBasedGame sb, int delta) throws SlickException {

		Input input = gc.getInput();

		int mouseX = input.getMouseX();
		int mouseY = input.getMouseY();

		//int mouseXPlateau=mouseX-xMin;
		//int mouseYPlateau=mouseY-yMin;

		//int mouseYScaled=(int) ((float)mouseYPlateau/((hautHexa-largHexa*0.25f)*scale));
		//int mouseXScaled=(int) (((float)(mouseXPlateau)-(mouseYScaled%2*largHexa*0.5f*scale))/(largHexa*scale));


		int mouseOverX=-1;
		int mouseOverY=-1;
		for (HexagonalButton h: listHexagonalButtons) {
			if(h.mouseOver()){mouseOverX=h.getxCase();mouseOverY=h.getyCase();}
		}
		Case caseCliquee=plateau.getCase(mouseOverX, mouseOverY);
		boolean mousePressed=input.isMousePressed(0);
		boolean uneCaseEstCliquee=(mousePressed&&caseCliquee!=null);
		Joueur jCourant=joueurs.get(Math.min(joueurCourant,joueurs.size()-1));

		boolean isLocalGame=true;
		for (Joueur j : joueurs) {
			if(!j.isLocalPlayer()) isLocalGame=false;
		}

		if((mousePressed)&&
				(currentState==STATES.PLACE_PIECE_STATE||
						currentState==STATES.SELECT_CASE_STATE||
						currentState==STATES.SELECT_PIECE_STATE||
						currentState==STATES.MOVING_PIECE_STATE||
						currentState==STATES.GAME_OVER_STATE
				)) {
			if (nouvellePartie.isMouseOver()) {
				currentState = STATES.PARAMETERS_GAME_STATE;
				joueurCourant=0;
				jCourant=joueurs.get(joueurCourant);
				pseudoField.setText(jCourant.getPseudo());
				for (Joueur j : joueurs) {
					j.initialiseArrayAndScore();
				}
				mousePressed=false;
			}
		}

		switch(currentState)
		{		
		case PARAMETERS_GAME_STATE:

			if(isLocalGame){
				if(mousePressed){
					initParametres(nbCasesField.getText(), nbJoueursField.getText(), nbPingouinsField.getText());	
					if(couleursImage.isMouseOver()){
						int x=couleursImage.getXmouse();
						int y=couleursImage.getYmouse();
						jCourant.setCouleur(couleursImage.getImage().getColor(x, y));
					}
					else if(suivantImage.isMouseOver()){
						if(pseudoField.getText()!="")jCourant.setPseudo(pseudoField.getText());
						joueurCourant=(joueurCourant+1)%joueurs.size();
						jCourant=joueurs.get(joueurCourant);
						pseudoField.setText(jCourant.getPseudo());
					}
					else if(okButton.isMouseOver()){
						if(pseudoField.getText()!="")jCourant.setPseudo(pseudoField.getText());
						currentState = STATES.PLACE_PIECE_STATE;
						joueurCourant=0;
						initBoard();
					}
					else if(cpu.isMouseOver()||humain.isMouseOver()){
						jCourant.setIsHuman(!jCourant.isHuman());
					}
				}
			}

			break;
		case PLACE_PIECE_STATE:

			if(jCourant.isLocalPlayer()&&jCourant.isHuman()){
				if(uneCaseEstCliquee) {
					if(jCourant.placePingouin(caseCliquee)) joueurCourant=(joueurCourant+1)%joueurs.size();
					else{
						// TODO la il faudrait selectionner les pingouins du joueur, pke il a pas cliqu� sur un bon
					}
				}
			}
			else if(!jCourant.isHuman()){
				ArrayList<Case> listeCases=plateau.getCasesPlateau();
				int maxSize=0;
				Case bestCase=null;
				for (Case caseCur : listeCases) {
					if(caseCur.getNbPoissons()==1&&caseCur.estLibre()){
						int size=plateau.casesAtteignablesEnPingouin(caseCur).size();
						if(size>maxSize){
							maxSize=size;
							bestCase=caseCur;
						}
					}
				}
				if(jCourant.placePingouin(bestCase)){
					joueurCourant=(joueurCourant+1)%joueurs.size();	
				}
			}
			boolean pingouinsTousPlaces = true;
			for (int i = 0; i < joueurs.size(); i++) {
				pingouinsTousPlaces=pingouinsTousPlaces&joueurs.get(i).pingouinsTousPlaces();
			}
			if(pingouinsTousPlaces){ currentState = STATES.SELECT_PIECE_STATE;}
			break;
		case SELECT_PIECE_STATE:
			if(uneCaseEstCliquee&&jCourant.isLocalPlayer()&&jCourant.isHuman()) {
				if(jCourant.selectionnePingouin(caseCliquee)) currentState = STATES.SELECT_CASE_STATE;
			}
			else if(!jCourant.isHuman())currentState = STATES.SELECT_CASE_STATE;
			break;
		case SELECT_CASE_STATE:
			if(jCourant.isLocalPlayer()&&jCourant.isHuman()){
				if(uneCaseEstCliquee){
					Pingouin pingouinSelectionne=jCourant.getPingouinSelectionne();
					if(pingouinSelectionne==null)currentState = STATES.SELECT_PIECE_STATE;
					else if(plateau.casesAtteignablesEnPingouin(pingouinSelectionne.getCase(),caseCliquee)) {
						plateau.selectionneCase(caseCliquee);
						currentState = STATES.MOVING_PIECE_STATE;
					}
					else if(jCourant.selectionnePingouin(caseCliquee)){	plateau.selectionneCase(null);}
				}
			}
			else if(!jCourant.isHuman())currentState = STATES.MOVING_PIECE_STATE;
			break;
		case MOVING_PIECE_STATE:
			if(jCourant.isLocalPlayer()&&jCourant.isHuman()){
				jCourant.deplacePingouinSelectionne(plateau.getCaseSelectionnee());
				plateau.selectionneCase(null);
				jCourant.initSelection();
				if(jeuFini())currentState = STATES.GAME_OVER_STATE;
				else{
					joueurCourant=(joueurCourant+1)%joueurs.size();
					while(jeuFini(joueurs.get(joueurCourant))){
						joueurCourant=(joueurCourant+1)%joueurs.size();
					}
					currentState = STATES.SELECT_PIECE_STATE;
				}
			}
			else if(!jCourant.isHuman()){
				Object[] bestChoice=plateau.getNextBestCase(joueurCourant, joueurs);
				
				jCourant.deplacePingouin((Pingouin)(bestChoice[0]),(Case)(bestChoice[1]));
				plateau.selectionneCase(null);
				
				if(jeuFini())currentState = STATES.GAME_OVER_STATE;
				else{
					joueurCourant=(joueurCourant+1)%joueurs.size();
					while(jeuFini(joueurs.get(joueurCourant))){
						joueurCourant=(joueurCourant+1)%joueurs.size();
					}
					currentState = STATES.SELECT_PIECE_STATE;
				}
				
			}
			break;
		case PAUSE_STATE:
			break;
		case GAME_OVER_STATE:
			break;
		case RETURN_TO_MENU_STATE:
			sb.enterState(PinguGame.MAINMENUSTATE);
			break;
		}
	}


	public boolean jeuFini() {
		for (int i = 0; i < joueurs.size(); i++) {
			Joueur joueurCour=joueurs.get(i);
			if(!jeuFini(joueurCour))return false;
		}
		return true;
	}

	public boolean jeuFini(Joueur leJoueur) {
		ArrayList<Pingouin> pingouins = leJoueur.getPingouins();
		for (int j = 0; j < pingouins.size(); j++) {
			Pingouin pingouinCour = pingouins.get(j);
			if (plateau.casesAtteignablesEnPingouin(pingouinCour.getCase()).size()>0){
				return false;
			}
		}
		return true;

	}

	private void drawParametersPage(Graphics g) {
		nbJoueursField.render(g);
		nbPingouinsField.render(g);		
		nbCasesField.render(g);			


		couleursImage.render(g);

		caseHexa.draw(largeurFenetre-200, 200);
		pinguCouleur.draw(largeurFenetre-200 ,200, 
				joueurs.get(Math.min(joueurCourant,joueurs.size()-1)).getCouleur());
		pinguDessus.draw(largeurFenetre-200, 200);
		
		if(joueurs.get(Math.min(joueurCourant,joueurs.size()-1)).isHuman()){
			humain.render(g);
		}else cpu.render(g);

		pseudoField.render(g);		
		suivantImage.render(g);

		okButton.render(g);

	}

	private void drawBoard(Graphics g) {
		g.drawString(joueurs.get(joueurCourant).getPseudo(), 160, 10);
		pinguCouleur.draw(260, 5,0.5f, joueurs.get(joueurCourant).getCouleur());
		pinguDessus.draw(260, 5,0.5f);
		nouvellePartie.render(g);

		for (int y = 0; y < hauteurP ; y++) {
			for (int x = 0; x < largeurP; x++) {
				Case caseCourante=plateau.getCase(x, y);
				if(caseCourante!=null&&caseCourante.isPasFondue()){
					float xPos=xMin+(x*largHexa*scale)+(y%2*largHexa*0.5f*scale);
					float yPos=yMin+(y*(hautHexa-largHexa*0.25f)*scale);
					caseHexa.draw(xPos,yPos, scale);
					if(caseCourante.getSelection()) caseSelection.draw(xPos,yPos, scale);
					int nbPoissons=caseCourante.getNbPoissons();
					Image imageCourante=getPoissons(nbPoissons);

					imageCourante.setCenterOfRotation(largHexa*0.5f*scale, hautHexa*0.5f*scale);
					imageCourante.setRotation((float) ((Math.sin(50.*scale*yPos)+Math.cos(50.*scale*xPos))*360));
					imageCourante.draw(xPos,yPos,scale);

					Pingouin pingouinCourant=caseCourante.getMonPingouin();
					if(pingouinCourant!=null){
						drawPingu(pingouinCourant,xPos,yPos,scale);
					}
				}
			}
		}
	}

	private void initBoard() {
		listHexagonalButtons=new ArrayList<HexagonalButton>();
		listHexagonalButtons.clear();
		for (int y = 0; y < hauteurP ; y++) {
			for (int x = 0; x < largeurP; x++) {
				Case caseCourante=plateau.getCase(x, y);
				if(caseCourante!=null&&caseCourante.isPasFondue()){
					float xPos=xMin+(x*largHexa*scale)+(y%2*largHexa*0.5f*scale);
					float yPos=yMin+(y*(hautHexa-largHexa*0.25f)*scale);
					HexagonalButton hcase=new HexagonalButton(container, null, (int)xPos, (int) yPos, scale,x,y);
					listHexagonalButtons.add(hcase);
				}
			}
		}
	}

	private void drawPause() {
		// TODO Auto-generated method stub

	}

	private void drawGameOver(Graphics g) {
		float scaleGameOver= (float)hauteurFenetre/(((float)(joueurs.size()+1)*(float)hautHexa)+100.f);
		int maxScore=0;

		nouvellePartie.render(g);

		for (int i = 0; i < joueurs.size(); i++) {
			Joueur jCourant=joueurs.get(i);
			int score=jCourant.getScore();
			maxScore=Math.max(maxScore, score);
		}
		for (int i = 0; i < joueurs.size(); i++) {
			Joueur jCourant=joueurs.get(i);
			int score=jCourant.getScore();
			if(maxScore==score)caseHexa.draw(100, 100+hautHexa*scaleGameOver*i, scaleGameOver);
			drawPingu(jCourant.getPingouins().get(0), 100, 100+hautHexa*scaleGameOver*i, scaleGameOver);
			g.drawString(jCourant.getPseudo()+": "+score, 100+largHexa*scaleGameOver,
					100+(hautHexa*scaleGameOver*0.25f)+hautHexa*scaleGameOver*i);

		}
	}


	private Image getPoissons(int nbPoissons){
		switch (nbPoissons) {
		case 2:
			return poisson2;
		case 3:
			return poisson3;
		default:
			return poisson1;
		}
	}

	private void drawPingu(Pingouin pingouin, float xPos, float yPos, float scale) {
		Color coul=pingouin.getJoueur().getCouleur();
		if (pingouin.getSelection()) {
			//pinguSelection.draw(xPos,yPos,scale);
			caseSelection.draw(xPos,yPos,scale);
		}
		pinguCouleur.draw(xPos,yPos,scale,coul);
		pinguDessus.draw(xPos,yPos,scale);

	}

}